﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;

namespace PaceR.Core.Extensions
{
    public static class StringExtensions
    {
        private static readonly string ellipsis = "...";

        #region Conversions

        /// <summary>
        /// convert string to int; null safe
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static int ToInt(this string s)
        {
            return ToInt(s, int.MinValue);
        }

        /// <summary>
        /// convert string to int; null safe
        /// </summary>
        /// <param name="s"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static int ToInt(this string s, int defaultValue)
        {
            int i;
            if (int.TryParse(s, out i))
                return i;
            return defaultValue;
        }

        public static long ToLong(this string s)
        {
            return ToLong(s, long.MinValue);
        }

        public static long ToLong(this string s, long defaultValue)
        {
            long l;
            if (long.TryParse(s, out l))
                return l;
            return defaultValue;
        }

        /// <summary>
        /// convert string to decimal; null safe
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static decimal ToDecimal(this string s)
        {
            return ToDecimal(s, decimal.MinValue);
        }

        /// <summary>
        /// convert string to decimal; null safe
        /// </summary>
        /// <param name="s"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static decimal ToDecimal(this string s, decimal defaultValue)
        {
            decimal d;
            if (decimal.TryParse(s, out d))
                return d;
            return defaultValue;
        }

        /// <summary>
        /// convert string to double; null safe
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static double ToDouble(this string s)
        {
            return ToDouble(s, double.MinValue);
        }

        /// <summary>
        /// convert string to double; null safe
        /// </summary>
        /// <param name="s"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static double ToDouble(this string s, double defaultValue)
        {
            double d;
            if (double.TryParse(s, out d))
                return d;
            return defaultValue;
        }

        /// <summary>
        /// convert string to guid; null safe
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static Guid ToGuid(this string s)
        {
            return ToGuid(s, Guid.Empty);
        }

        /// <summary>
        /// convert string to guid; null safe
        /// </summary>
        /// <param name="s"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static Guid ToGuid(this string s, Guid defaultValue)
        {
            Guid g;
            if (Guid.TryParse(s, out g))
                return g;
            return defaultValue;
        }

        public static CultureInfo ToCultureInfo(this string s)
        {
            return ToCultureInfo(s, System.Threading.Thread.CurrentThread.CurrentCulture);
        }

        public static CultureInfo ToCultureInfo(this string s, CultureInfo defaultCulture)
        {
            try
            {
                return CultureInfo.CreateSpecificCulture(s);
            }
            catch (Exception)
            {
                return defaultCulture;
            }
        }

        public static DateTime ToDateTime(this string s)
        {
            return ToDateTime(s, default(DateTime));
        }

        public static DateTime ToDateTime(this string s, DateTime defaultValue)
        {
            DateTime date = DateTime.MinValue;
            if (DateTime.TryParse(s, out date))
                return date;
            return defaultValue;
        }

        #endregion Conversions

        #region Validation

        public static bool IsNullOrEmptyOrWhitespace(this string value)
        {
            return value == null || value.Trim().Length == 0;
        }

        public static bool ValidateMaxLength(this string value, int length)
        {
            return value == null || value.Length <= length;
        }

        public static bool ValidateMinLength(this string value, int length)
        {
            return value != null && value.Length >= length;
        }

        public static bool ValidateLengthRange(this string value, int minLength, int maxLength)
        {
            return value.ValidateMinLength(minLength) && value.ValidateMaxLength(maxLength);
        }

        public static bool ValidateLengthOutsideRange(this string value, int lowerBound, int upperBound)
        {
            return value == null || !value.ValidateMinLength(lowerBound) || !value.ValidateMaxLength(upperBound);
        }

        public static bool ValidatePattern(this string value, string pattern)
        {
            return Regex.IsMatch(value, pattern);
        }

        #endregion Validation

        #region Transformations

        /// <summary>
        /// Splits a camelCase string into separate words and capitalizes the first word; null safe
        /// </summary>
        /// <param name="target"></param>
        /// <returns></returns>
        public static string SplitCamelCase(this string target)
        {
            if (!string.IsNullOrEmpty(target))
            {
                string transformed = target.Trim();
                var sb = new StringBuilder();
                foreach (char c in transformed.ToCharArray())
                {
                    if (char.IsUpper(c) && sb.Length > 0) sb.Append(' ');
                    if (sb.Length == 0 && char.IsLower(c))
                    {
                        sb.Append(char.ToUpper(c));
                        continue;
                    }
                    sb.Append(c);
                }
                return sb.ToString();
            }
            return target;
        }

        /// <summary>
        /// Returns a string truncated to the given length; null safe
        /// </summary>
        /// <param name="target"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public static string Truncate(this string target, int length)
        {
            if (!string.IsNullOrEmpty(target) && target.Length > length)
            {
                target = target.Substring(0, length);
            }
            return target;
        }

        /// <summary>
        /// Returns a string with ellipsis(...) truncated to the given length; null safe
        /// </summary>
        /// <param name="target"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public static string TruncateWithEllipsis(this string target, int length)
        {
            string truncated = Truncate(target, length - 3);
            if (!string.IsNullOrEmpty(truncated) && truncated.Length < target.Length) 
                truncated = AddEllipsis(truncated);
            return truncated;
        }

        /// <summary>
        /// Returns a string truncated by the given length and ellipsis(...) added; null safe
        /// </summary>
        /// <param name="target"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public static string TruncateAndAddEllipsis(this string target, int length)
        {
            string truncated = Truncate(target, length);
            if (truncated.Length < target.Length)
                truncated = AddEllipsis(truncated);
            return truncated;
        }

        /// <summary>
        /// Adds ellipsis (...) to the end of the string; null safe
        /// </summary>
        /// <param name="target"></param>
        public static string AddEllipsis(this string target)
        {
            if (target != null)
                target += ellipsis;
            return target;
        }

        /// <summary>
        /// Appends a string with a separator if append string exists
        /// </summary>
        /// <param name="target"></param>
        /// <param name="append"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string AppendWithSeparator(this string target, string append, string separator = " ")
        {
            if (!string.IsNullOrEmpty(target) && !string.IsNullOrEmpty(append))
                target = string.Format("{0}{1}{2}", target, separator, append);
            else if (!string.IsNullOrEmpty(append))
                target = append;
            return target;
        }

        public static string FileExtensionFromPath(this string path)
        {
            if (!string.IsNullOrEmpty(path))
            {
                return path.Substring(path.LastIndexOf('.') + 1);
            }
            return path;
        }

        #endregion Transformations
    }
}
